/**
 * 
 */
package primeFinder;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;

/**
 * @author mfan
 *
 */
public final class FindPrimeConcurrent extends AbstractPrimeFinder{

	final private int poolSize;
	
	// Number of sub-tasks after the original task has been divided
	final private int taskNumber;

	/**
	 * @param poolSize
	 * @param taskNumber
	 */
	public FindPrimeConcurrent(final int poolSize, final int taskNumber) {
		this.poolSize = poolSize;
		this.taskNumber = taskNumber;
	}

	/* (non-Javadoc)
	 * @see primeFinder.AbstractPrimeFinder#countPrime(long)
	 */
	@Override
	protected long countPrime(long high) {
		// TODO Auto-generated method stub
		
		final long segmentLength = high/taskNumber;
		// Prepare a bunch of tasks that will be submitted to thread pool
		final List<Callable<Long>> bunchOfTasks = new ArrayList<>();
		for (int i = 0; i < taskNumber; i++) {
			final long start = (i * segmentLength) + 1;
			final long end = (i + 1) * segmentLength;
			System.out.println(start + ":" + end);
			bunchOfTasks.add(new Callable<Long>() {
				@Override
				public Long call() throws Exception {
					// TODO Auto-generated method stub
					return countPrimesInRange(start, end);
				}
			});
		}
		// Create thread pool
		final ExecutorService threadPool = Executors.newFixedThreadPool(poolSize);
		//
		long primeCount = 0;
		try {
			final List<Future<Long>> bunchOfResults = threadPool.invokeAll(bunchOfTasks, 1000, TimeUnit.SECONDS);
			//
			for (Future<Long> oneResult : bunchOfResults) {
				primeCount += oneResult.get();
			}
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (ExecutionException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} finally {
			threadPool.shutdown();
		}
		
		return primeCount;
	}
	
	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		(new FindPrimeConcurrent(4,4)).computeAndGetTiming(10000000); 
	}

}
